/**
 * 创建一个Promise对象的实例
 * @param name {string} 该实例的名称
 * @param flag {boolean} 返回的结果状态：完成还是拒绝
 * @param diff {number} 延迟的时间
 */
let createPromiseCase = (name, flag, diff) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      flag ? resolve(name) : reject(new Error('testPromise is error, name: ' + name));
    }, diff);
  });
};

let p1_suc_100 = createPromiseCase('p1-suc-100', true, 100);
let p2_suc_200 = createPromiseCase('p2-suc-200', true, 200);
let p3_suc_300 = createPromiseCase('p3-suc-300', true, 300);
let p4_fail_100 = createPromiseCase('p4-fail-100', false, 100);
let p5_fail_200 = createPromiseCase('p5-fail-200', false, 200);
let p6_fail_400 = createPromiseCase('p5-fail-400', false, 400);

/*
Promise.finally
场景：无论promise执行成功或者失败的，都会走一下finally方法，做一下资源释放的工作。类似try catch finally。
*/
Promise.prototype.finally = function (callback) {
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};

new Promise((resolve, reject) => {
  resolve();
}).finally(() => {
  console.log('finally1');
}).then(() => {
  console.log('then');
}).finally(() => {
  console.log('finally2');
});

/*
Promise.first
场景：一个页面当前正处于loading状态，同时请求了多个接口，无论哪个接口正确返回结果，则loading效果取消！或者其他的要获取获取第一个完成状态的值
*/
Promise.first = (promiseList) => {
  return new Promise((resolve, reject) => {
    let i = 0;
    promiseList.forEach(p => {
      p.then(resolve).catch(() => {
        if (++i === promiseList.length) {
          reject('All promises not resolve')
        }
      });
    })
  })
}

// Promise.first([p3_suc_300, p2_suc_200, p1_suc_100])
//   .then(res => console.log(res)) // p1_suc_100
//   .catch(e => console.error(e))


/*
Promise.last
与Promise.first对应的则是Promise.last，获取最后变成完成状态的值。这里与Promise.first不同的是，
只有最后一个Promise都变成最终态（完成或拒绝），才能知道哪个是最后一个完成的，这里我采用了计数的方式，then和catch只能二选一，等计数器达到list.length时，执行外部的resolve。
*/
Promise.last = promiseList => {
  return new Promise((resolve, reject) => {
    let i = 0;
    let lastResult = null;
    const fn = () => {
      if (++i === promiseList.length) {
        lastResult === null ? reject('All promises not resolve') : resolve(lastResult);
      }
    }
    promiseList.forEach(p => {
      p.then(res => {
        lastResult = res;
        fn()
      }, () => {
        fn()
      });
    })
  })
}

// Promise.last([p1_suc_100, p2_suc_200, p4_fail_100, p3_suc_300, p5_fail_200])
//   .then(res => console.log(res)) //p3_suc_300
//   .catch(e => console.error(e))


/*
Promise.none
Promise.none与Promise.all正好相反，所有的promise都被拒绝了，则Promise.none变成完成状态。
该方法可以用Promise.first来切换，当执行Promise.first的catch时，则执行Promise.none中的resolve。
*/

Promise.none = promiseList => {
  return new Promise((resolve, reject) => {
    let i = 0;
    let results = [];
    promiseList.forEach(p => {
      p.then(() => {
        reject('Some one resolved');
      }, (err) => {
        results.push(err.message);
        if (++i === promiseList.length) {
          resolve(results);
        }
      });
    })
  })
}

// Promise.none([p4_fail_100, p6_fail_400])
//   .then(res => console.log(res))
//   .catch(e => console.error(e))


/*
Promise.any
Promise.any表示只获取所有的promise中进入完成状态的结果，被拒绝的则忽略掉。
*/
Promise.any = promiseList => {
  return new Promise((resolve, reject) => {
    let i = 0;
    let results = [];
    let fn = () => {
      if (++i === promiseList.length) {
        resolve(results);
      }
    }
    promiseList.forEach(p => {
      p.then((res) => {
        results.push(res);
        fn();
      }, (err) => {
        fn();
      });
    })
  })
}

// Promise.any([p1_suc_100, p2_suc_200, p4_fail_100, p3_suc_300, p6_fail_400])
//   .then(res => console.log(res)) // ["p1-suc-100", "p2-suc-200", "p3-suc-300"]
//   .catch(e => console.error(e))